package cn.virens.database.common;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;

import cn.hutool.core.util.ArrayUtil;
import cn.virens.components.page.PageParam;
import cn.virens.components.page.PageResult;
import cn.virens.exception.APIException;
import tk.mybatis.mapper.entity.Example;

/**
 * 通用service实现类
 * 
 * @文件   :BaseServiceImpl.java
 * @作者   :cn.loioi
 * @创建时间 :2016年10月13日 下午1:24:27
 */
public abstract class BaseServiceImpl<M extends BaseMapper<T>, T> implements BaseService<T> {
	protected final Logger logger = LoggerFactory.getLogger(getClass());

	protected final Class<T> clazz;

	@Autowired
	protected M mBaseMapper;

	public BaseServiceImpl(Class<T> clazz) {
		this.clazz = clazz;
	}

	/**
	 * 插入一条数据
	 */
	@Override
	@Transactional(readOnly = false)
	public T insert(T record) {
		if (record == null) { return null; }

		// 插入setCreateTime
		invoke(record, "setCreateTime", new Date());
		invoke(record, "setUpdateTime", new Date());

		if (mBaseMapper.insertSelective(record) > 0) {
			return record;
		} else {
			return null;
		}
	}

	/**
	 * 更新一条数据
	 */
	@Override
	@Transactional(readOnly = false)
	public T update(T record) {
		if (record == null) { return null; }

		// 插入setUpdateTime
		invoke(record, "setUpdateTime", new Date());

		if (mBaseMapper.updateByPrimaryKeySelective(record) > 0) {
			return record;
		} else {
			return null;
		}
	}

	/**
	 * 删除一条数据
	 */
	@Override
	@Transactional(readOnly = false)
	public int delete(Serializable id) {
		return mBaseMapper.deleteByPrimaryKey(id);
	}

	@Override
	@Transactional(readOnly = true)
	public List<? extends T> selectAll(Map<String, Object> param) {
		return mBaseMapper.selectByExample(ExampleWrapper.of(clazz, param));
	}

	@Override
	@Transactional(readOnly = true)
	public T selectOne(Map<String, Object> param) {
		if (param != null && param.isEmpty() == false) {
			return selectOne(ExampleWrapper.of(clazz, param));
		} else {
			throw new APIException("Null", "param is null!");
		}
	}

	@Override
	@Transactional(readOnly = true)
	public T selectOne(Serializable id) {
		return mBaseMapper.selectByPrimaryKey(id);
	}

	@Override
	@Transactional(readOnly = true)
	public PageResult<?> selectPage(PageParam pageParam) {
		return doPageSelect(pageParam, (param) -> {
			return doPageQuery(param);
		});
	}

	protected Object invoke(T record, String methodName, Object... parameter) {
		try {
			Class<?>[] parameterTypes = new Class<?>[parameter.length];
			for (int i = 0; i < parameterTypes.length; i++) {
				parameterTypes[i] = parameter[i].getClass();
			}

			Method method = clazz.getMethod(methodName, parameterTypes);

			if (method != null) {
				return method.invoke(record, parameter);
			} else {
				return null;
			}
		} catch (Exception e) {
			logger.error("执行指定方法异常：" + e.getMessage());
		}

		return null;
	}

	/**
	 * 查询一条记录
	 * 
	 * @param  example
	 * @return
	 */
	protected T selectOne(Example example) {
		return mBaseMapper.selectOne(example);
	}

	/**
	 * 默认查询全部，如需使用分页，并且有条件查询，复写该方法
	 * 
	 * @param  param
	 * @return       @
	 */
	protected List<?> doPageQuery(Map<String, Object> param) {
		return selectAll(param);
	}

	/**
	 * 进行分页查询
	 * 
	 * @param pageParam
	 * @param action
	 */
	protected final <R> PageResult<R> doPageSelect(PageParam pageParam, Function<Map<String, Object>, List<R>> action) {
		PageResult<R> answer = new PageResult<>();
		try {
			// 获取分页参数
			int pageNum = pageParam.getPageNum();
			int pageSize = pageParam.getPageSize();

			// 设置分页信息
			Page<Object> _page = PageMethod.startPage(pageNum, pageSize);
			_page.setCount(pageParam.isCount());
			_page.setOrderBy(pageParam.getOrderBy());

			// 执行查询
			List<R> list = action.apply(pageParam.getParams());

			// 获取查询结果中的分页信息
			if (list != null && list.isEmpty() == false) {
				PageInfo<R> pageInfo = PageInfo.of(list);

				answer.setList(pageInfo.getList());
				answer.setSize(pageInfo.getSize());
				answer.setTotal(pageInfo.getTotal());
				answer.setPages(pageInfo.getPages());
				answer.setPageNum(pageInfo.getPageNum());
				answer.setPageSize(pageInfo.getPageSize());
			}
		} finally {
			PageMethod.clearPage();
		}

		return answer;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected static Iterable<Object> criteriaIn(Map<String, Object> param, String key) {
		Object val = (param == null ? null : param.get(key));

		Collection<Object> answer = null;
		if (ArrayUtil.isArray(val)) {
			answer = Arrays.asList((Object[]) val);
		} else if (val instanceof Collection) {
			answer = (Collection<Object>) val;
		} else if (val instanceof Map) {
			answer = ((Map) val).values();
		} else if (val != null) {
			answer = Arrays.asList(val);
		} else {
			return null;
		}

		// 如果返回值为空就返回null
		if (answer != null && !answer.isEmpty()) {
			return answer;
		} else {
			return null;
		}
	}

	protected static String criteriaLike(Map<String, Object> param, String key) {
		Object val = param == null ? null : param.get(key);

		if (val != null) {
			return "%" + val + "%";
		} else {
			return null;
		}
	}

	protected static Object criteriaEqual(Map<String, Object> param, String key) {
		return param == null ? null : param.get(key);
	}
}
